//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// (C) Copyright 2006 Marvell International Ltd.
// All Rights Reserved
//
/*++
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:  

Abstract:

    Platform dependent Serial definitions for XSCALE 16550  controller.

Notes: 
--*/
#ifndef __PXA16550_H_
#define __PXA16550_H_
#include "monahans.h"

#include <ceddk.h>
#include "xllp_dmac.h"
#include "xllp_uart_proc.h"
#include "xllp_irda_proc.h"
#include "dmawince.h"
#include "ipm_api.h"


#define FFUART_RIL_RING_INDICATE_EVENT_NAME   TEXT("FFUART_RIL_RING_INDICATE_EVENT")
#define FFUART_RIL_DSR_EVENT               1
#define FFUART_RIL_RING_EVENT              2
#define FFUART_RIL_INTERNAL_EVENT          3

#define DELAY_FOR_FIFO_EMPTY_MAXVALUE  8000 // us.
#define DELAY_FOR_FIFO_EMPTY_INTERVAL  5 // us.


#define MAX_NAMELEN         128

#define PXA_SERIAL_FIFO_DEPTH 64
// For PXA only
// Extended EIR
//
#define PXA_SERIAL_IER_RTOIE 0x10 
#define PXA_SERIAL_IER_NRZE  0x20
#define PXA_SERIAL_IER_UUE   0x40
#define PXA_SERIAL_IER_DMAE  0x80
#define PXA_SERIAL_IER_HSE   0x100

// Enabling this bit in the fifo control register will turn
// on the fifos.  If the fifos are enabled then the high two
// bits of the interrupt id register will be set to one.  Note
// that this only occurs on a 16550 class chip.  If the high
// two bits in the interrupt id register are not one then
// we know we have a lower model chip.

// PXA 16550 Register Extra Bit.
//Additonal PXA bits
#define SERIAL_FCR_TX_INTR_LEVEL       ((UCHAR)0x08)
#define SERIAL_FCR_TRAILING_BYTES      ((UCHAR)0x10)
#define SERIAL_FCR_PERIPHERAL_BUS      ((UCHAR)0x20)
#define SERIAL_FCR_MASK      ((UCHAR)0xF9)

//auto-flow Control Enable
#define SERIAL_MCR_AFE 0x20 

#define SERIAL_IIR_EOC 0x20
#define SERIAL_IIR_ABL 0x10

//
// This set of values define the high water marks (when the
// interrupts trip) for the receive fifo.
//
#define SERIAL_32_BYTE_HIGH_WATER ((UCHAR)0xc0)

//For PXA only: 
#define PXA_SLOW_IR_SELECT_REGISTER    0x08
//The following macros are used in IR mode only

//To enable Transmitter SIR
#define INFRARED_ISR_TRANSMIT_SIR_ENABLE   (0x01)

//To enable Receiver SIR
#define INFRARED_ISR_RECEIVE_SIR_ENABLE    (0x02)

//To select Transmit Pulse Width
//If 1, the transmit pulse width is 1.6us. 
//If 0, it is 3/16 of a bit time width.
#define INFRARED_ISR_XMODE                 (0x04)

//Transmit Data Polarity:
//If 1, negative pulse is generated for a zero data bit. 
//If 0, a positive pulse is generated for a zero data bit.
#define INFRARED_ISR_TX_DATA_POLARITY      (0x08)

//Receive Data Polarity:
//If 1, a negative pulse is taken as a zero data bit. 
//If 0, a positive pulse is taken as a zero data bit.
#define INFRARED_ISR_RX_DATA_POLARITY      (0x10)

//Defines for workaround

// Use nDSR (intead of nDCD) for automatic detection of docking for serial port
//
// DCD signal is incorrect on some boards: is always LOW and never changes
// This works around is to detect DSR signal instead
// as DSR & CD are jumpered for serial null-modem cable (DB9-DB9).
//
#define AUTODETECT_USING_DSR 1

// Clear alternate function of GPIO#33 to be 0
//
// Need to clear GPIO#33 Altternate Function to be zero,
// because currently in StartUp() of OAL, default value will set GPIO#33 as Input AF 2 (FFDSR).
// 2 FFDSR caused no FFDSR interrupt is generated.
//
// Will turn OFF this flag after XLLI changes their logc.
//
#define CLEAR_GPIO33_AF 0

//UART: TX interrupt can be missed when running full duplex   
//Tibet ID:1981078
//The TX interrupt can be missed due to the state machine getting locked into an intermediate state when a higher priority interrupt de-asserts just before the IIR register is read.
//Transmits could stall if this situation occurs.
//When running full duplex, if any interrupt occurs, check LSR[TDRQ] for status on the transmit FIFO. If TDRQ is set, the FIFO is half or more empty and data needs to be written to it. After the write to the transmit FIFO the state machine operates normally.
//DMA mode is not affected by this sighting.

#define TX_INTE_MISSING_WHEN_FULL_DUPLEX 1

#include "pdd16550.h"


//Note: This typedef is copied from "serpriv.h" in com_mdd folder
// They should be kept synchronized!
//

typedef struct __RX_BUFFER_INFO {
    ULONG   Read;               /* @field Current Read index. */
    ULONG   Write;              /* @field Current Write index. */
    ULONG   Length;             /* @field Length of buffer */
    BOOL    DataAvail;          /* @field BOOL reflecting existence of data. */
    PUCHAR  RxCharBuffer;       /* @field Start of buffer */
    CRITICAL_SECTION    CS;     /* @field Critical section */
    } RX_BUFFER_INFO, *PRX_BUFFER_INFO;

#define RxResetFifo(pSH)   pSH->RxBufferInfo.Write = pSH->RxBufferInfo.Read = 0
#define RxEnterCS(pSH)     EnterCriticalSection (&(pSH->RxBufferInfo.CS))
#define RxLeaveCS(pSH)     LeaveCriticalSection (&(pSH->RxBufferInfo.CS))
#define RxWrite(pSH)       (pSH->RxBufferInfo.Write)
#define RxRead(pSH)        (pSH->RxBufferInfo.Read)
#define RxLength(pSH)      (pSH->RxBufferInfo.Length)
// Don't use the power of 2 trick for length, because the PDD has option of overriding
// buffer length, and may not specify a power of 2.  Lets be more flexible & a very
// little bit slower.
// #define RxBytesAvail(pSH)  ((RxWrite(pSH) - RxRead(pSH)) & (RxLength(pSH) - 1))

#define RxBuffWrite(pSH)   (pSH->RxBufferInfo.RxCharBuffer+pSH->RxBufferInfo.Write)
#define RxBuffRead(pSH)    (pSH->RxBufferInfo.RxCharBuffer+pSH->RxBufferInfo.Read)

typedef struct __TX_BUFFER_INFO {
    DWORD   Permissions;        /* @field Current permissions */
    ULONG   Read;               /* @field Current Read index. */
    ULONG   Length;             /* @field Length of buffer */
    PUCHAR  TxCharBuffer;       /* @field Start of buffer */
    CRITICAL_SECTION    CS;     /* @field Critical section */
} TX_BUFFER_INFO, *PTX_BUFFER_INFO;

#define TxEnterCS(pSH)     EnterCriticalSection (&(pSH->TxBufferInfo.CS))
#define TxLeaveCS(pSH)     LeaveCriticalSection (&(pSH->TxBufferInfo.CS))
#define TxRead(pSH)        (pSH->TxBufferInfo.Read)
#define TxLength(pSH)      (pSH->TxBufferInfo.Length)
#define TxBytesAvail(pSH)  (TxLength(pSH)-TxRead(pSH))
#define TxBuffRead(pSH)    (pSH->TxBufferInfo.TxCharBuffer+pSH->TxBufferInfo.Read)


// @struct  HW_INDEP_INFO | Hardware Independent Serial Driver Head Information.
typedef struct __HW_INDEP_INFO {
    CRITICAL_SECTION    TransmitCritSec1;       // @field Protects tx action
    CRITICAL_SECTION    ReceiveCritSec1;        // @field Protects rx action

    PHWOBJ          pHWObj;         // @field Represents PDD object.
    PVOID           pHWHead;        // @field Device context for PDD.
    
    HANDLE          hSerialEvent;   // @field Serial event, both rx and tx
    HANDLE          hReadEvent;     // @field Serial event, both rx and tx
    HANDLE          hKillDispatchThread;    // @field Synchonize thread end
    HANDLE          hTransmitEvent; // @field transmit event, both rx and tx
    HANDLE          pDispatchThread;// @field ReceiveThread 
    ULONG           Priority256;    // @field CeThreadPriority of Dispatch Thread.
    ULONG           DroppedBytesMDD;// @field Record of bytes dropped by MDD.
    ULONG           DroppedBytesPDD;// @field Record of bytes dropped by PDD.
    ULONG           RxBytes;        // @field Record of total bytes received.
    ULONG           TxBytes;        // @field Record of total bytes transmitted.
    ULONG           TxBytesPending; // @field Record of total bytes awaiting transmit.
    ULONG           TxBytesSent;    // @field Record of bytes sent in one transmission
    DCB             DCB;            // @field DCB (see Win32 Documentation.
    COMMTIMEOUTS    CommTimeouts;   // @field Time control field. 
    DWORD           OpenCnt;        // @field Protects use of this port 
    DWORD           KillRxThread:1; // @field Flag to terminate SerialDispatch thread.
    DWORD           XFlow:1;        // @field True if Xon/Xoff flow ctrl.
    DWORD           StopXmit:1;     // @field Stop transmission flag.
    DWORD           SentXoff:1;     // @field True if XOFF sent.
    DWORD           DtrFlow:1;      // @field True if currently DTRFlowed   
    DWORD           RtsFlow:1;      // @field True if currently RTSFlowed
    DWORD           fAbortRead:1;   // @field Used for PURGE
    DWORD           fAbortTransmit:1;// @field Used for PURGE
    DWORD           Reserved:24;    // @field remaining bits.
    ULONG           fEventMask;     // @field Sum of event mask for all opens
    RX_BUFFER_INFO  RxBufferInfo;   // @field rx buffer info.
    TX_BUFFER_INFO  TxBufferInfo;   // @field tx buffer info.


    LIST_ENTRY      OpenList;       // @field Head of linked list of OPEN_INFOs    
    CRITICAL_SECTION OpenCS;        // @field Protects Open Linked List + ref counts

} HW_INDEP_INFO, *PHW_INDEP_INFO;


#define UART_FIFO_MODE_INTR 0
#define UART_FIFO_MODE_DMA 1

#define UART_DMA_TX_BUFFER_SIZE (1024L)   //size of Tx buffer, in bytes
#define UART_DMA_RX_BUFFER_SIZE (1024L)   //size of Rx, in bytes

#define PC_REG_SERIALIRCONNECTED_VAL_NAME TEXT("IRConnected")
#define PC_REG_SERIALIRCONNECTED_VAL_LEN  sizeof(DWORD)

#define PC_REG_SERIALFIFOMODE_VAL_NAME TEXT("FIFOMode")
#define PC_REG_SERIALFIFOMODE_VAL_LEN  sizeof(DWORD)

#define PC_REG_SERIAL32BITBUS_VAL_NAME TEXT("32BitBus")
#define PC_REG_SERIAL32BITBUS_VAL_LEN  sizeof(DWORD)

#define PC_REG_SERIALAUTOFLOWCONTROL_VAL_NAME TEXT("AutoFlowControl")
#define PC_REG_SERIALAUTOFLOWCONTROL_VAL_LEN  sizeof(DWORD)

#define PC_REG_SERIALFRIENDLYNAME_PATH TEXT("Drivers\\BuiltIn\\Serial\\Unimodem")
#define PC_REG_SERIALFRIENDLYNAME_VAL_NAME TEXT("FriendlyName")

#define PC_REG_SERIALFICLASS_VAL_NAME TEXT("IClass")



//Toggle message ON/OFF
//#define MY_RETAILMSG RETAILMSG
#define MY_RETAILMSG //RETAILMSG

#define UART_DEBUG 0

class CPXAReg16550: public CReg16550 {
public:
    CPXAReg16550(PPXA_UART_REG pRegAddr);
    virtual BOOL    Init() { return (m_pRegAddr!=NULL); } ;
    // We do not virtual Read & Write data because of Performance Concern.
    virtual void    Write_DATA(UINT8 uData) { WRITE_REGISTER_ULONG((PULONG) &(m_pRegAddr->thr_rbr_dll), uData); };
    virtual UINT8   Read_Data() { return (UCHAR)READ_REGISTER_ULONG((PULONG)&(m_pRegAddr->thr_rbr_dll)); } ;
    virtual void    Write_IER(UINT8 uData) { WRITE_REGISTER_ULONG((PULONG)&(m_pRegAddr->ier_dlh), uData); };
    virtual UINT8   Read_IER() { return (UCHAR)READ_REGISTER_ULONG((PULONG)&(m_pRegAddr->ier_dlh)); };
    virtual void    Write_FCR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->iir_fcr), uData);m_FCR = uData; };
    virtual UINT8   Read_FCR() { return m_FCR; }; // FCR is a write-only register
    virtual UINT8   Read_IIR() { return (UCHAR)READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->iir_fcr)) ;};
    virtual void    Write_LCR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->lcr), uData);};
    virtual UINT8   Read_LCR() { return (UCHAR)READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->lcr));};
    virtual void    Write_MCR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->mcr), uData);};
    virtual UINT8   Read_MCR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->mcr) );};
    virtual void    Write_LSR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->lsr), uData);};
    virtual UINT8   Read_LSR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->lsr) );};
    virtual void    Write_MSR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->msr), uData) ; };
    virtual UINT8   Read_MSR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->msr)); };
    virtual void    Write_SCR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->scr), uData );};
    virtual UINT8   Read_SCR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->scr)); };
    virtual void    Write_IER32(UINT32 uData) { WRITE_REGISTER_ULONG((PULONG)&(m_pRegAddr->ier_dlh), uData); };
    virtual UINT32   Read_IER32() { return (UINT32)READ_REGISTER_ULONG((PULONG)&(m_pRegAddr->ier_dlh)); };


    virtual void    Backup();
    virtual void    Restore();
// Here is specific for the XSCALE IR
    virtual void    Write_SIR(UINT8 uData) { WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->irdasel), uData);};
    virtual UINT8    Read_SIR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->irdasel)); };
// Here is specific for the PXA
    virtual UINT8   Read_FIOR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->fior)); };
    virtual UINT8   Read_ABR() { return (UCHAR) READ_REGISTER_ULONG( (PULONG)&(m_pRegAddr->abr));};
    virtual void    Write_ABR(UINT8 uData) {  WRITE_REGISTER_ULONG( (PULONG)&(m_pRegAddr->abr),uData);};
private:
    PPXA_UART_REG m_pRegAddr;
    BYTE    m_SIRBackup;

};


class CPXAPdd16550: public CPdd16550{
public:
    CPXAPdd16550 (LPTSTR lpActivePath, PVOID pMdd, PHWOBJ pHwObj);
    virtual ~CPXAPdd16550();
    virtual BOOL Init();
    virtual void   PostInit();
    virtual BOOL InitialEnableInterrupt(BOOL bEnable );
    virtual BOOL InitReceive(BOOL bInit);
    virtual BOOL InitXmit(BOOL bInit);
    virtual BOOL InitModem(BOOL bInit);
    virtual BOOL Open();
    virtual BOOL Close();
    virtual BOOL MapHardware();
    virtual BOOL CreateHardwareAccess();
    virtual DWORD   GetWaterMark();
    virtual BYTE  GetWaterMarkBit();
    virtual ULONG  GetModemStatus();
    virtual BYTE     GetLineStatus();
    virtual void      LineInterruptHandler();
    virtual ULONG   ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen);
    virtual void      DMA_ReceiveHandler();
    virtual BOOL    EnableXmitInterrupt(BOOL fEnable);
    virtual void     XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen);
    virtual void     XmitComChar(UCHAR ComChar);
    virtual DWORD  GetWriteableSize();  
    virtual BOOL    InitIR(BOOL bSet);
    virtual void     SetOutputMode(BOOL UseIR, BOOL Use9Pin);
    virtual BOOL    GetDivisorOfRate(ULONG BaudRate,PULONG pulDivisor);
    virtual BOOL    SetBaudRate(ULONG BaudRate,BOOL /*bIrModule*/);    
    virtual BOOL    SetDCB(LPDCB lpDCB);
    CPXAReg16550 *GetRegister() { return (CPXAReg16550 *)m_pReg16550; };

protected:
    volatile PPXA_UART_REG      m_pBaseAddress;
    volatile PPXA_GPIO_REG      m_pGPIOReg;
    volatile PPXA_CLKMGR_REG    m_pDCCLKReg;
    volatile unsigned int       *m_pMFPReg;
    volatile P_XLLP_MFP_RM_DB_ID_T m_pMfpRMDb;
    volatile HANDLE m_MfpRMDbHandle;
    volatile P_XLLP_OST_T 		m_pOSTRegs ; //OS timer counter register used to control the transmission.
     // Power Callback.
    //Commenting for now
    //virtual void    SerialRegisterBackup() ;

    BOOL Enable_IR_Rx_Tx(BOOL Rxenable, BOOL Txenable);
    BOOL m_fIRConnected;
    ULONG   PIO_ReceiveInterruptHandler(PUCHAR pRxBuffer,ULONG *pBufflen);
    void    PIO_XmitInterruptHandler(PUCHAR pTxBuffer, ULONG *pBuffLen);

    void DMAWriteBuffer(PUCHAR pTxBuffer, ULONG *pBuffLen);
    ULONG   DMAReadBuffer(PUCHAR pRxBuffer,ULONG *pBufflen);
    BOOL DMAInit();
    BOOL DMATXInit();
    BOOL DMARXInit();
    BOOL DMAReInitRXChannel();
    void  DMADeInit();
    DWORD ThreadRun();
    void DMA_XmitHandler(PUCHAR pTxBuffer, ULONG *pBuffLen);
    
    PHW_INDEP_INFO  m_pMDDSerialHead;   
    CLockObject      m_DMAC_HardwareLock;     // Critical section for accessing DMA controller directly
    
    BYTE m_DMAEnabled;      // Flag indicates if DMA is enabled
    BYTE m_32BitBusEnabled;     // Flag indicates if 32bit bus is enabled
    BYTE m_AutoFlowControlEnabled;   //Flag indicates if auto flow control is enabled
    
    DMA_ADAPTER_OBJECT m_DmaAdapter;
    PHYSICAL_ADDRESS m_PA;

    P_XLLP_DMAC_T m_DMAC_TX_Handle;
    P_XLLP_DMAC_T m_DMAC_RX_Handle;
    XLLP_UART_HANDLE_T  m_UART_Handle;
    XLLP_IRDA_HANDLE_T  m_IRDA_Handle;
    
    XLLP_UINT32_T  m_DMATxFIFO_physical;        // physical address of DMA Tx FIFO
    XLLP_DMAC_DRCMR_T m_cmrTxType;              //CMR type for Tx   
    XLLP_DMAC_CHANNEL_T m_DMATxChannel;     // DMA channel for Tx
    volatile HANDLE m_DMATxEvent;                      // DMA event for Tx
    volatile PBYTE  m_DMATxBuffer;                       // virtual address of DMA buffer for Tx    
    volatile PBYTE  m_DMATxBuffer_phy;               // physical address of DMA buffer for Tx
    volatile PBYTE  m_DMATxDescriptor;                // virtual address of DMA descriptor for Tx
    volatile PBYTE  m_DMATxDescriptor_phy;        // physical address of DMA descriptor for Tx

    XLLP_UINT32_T  m_DMARxFIFO_physical;       // physical address of DMA Rx FIFO
    XLLP_DMAC_DRCMR_T m_cmrRxType;             //CMR type for Rx    
    XLLP_DMAC_CHANNEL_T m_DMARxChannel;     // DMA channel for Rx
    volatile HANDLE m_DMARxEvent;                      // DMA event for Rx
    volatile PBYTE  m_DMARxBuffer;                      // virtual address of DMA buffer for Rx 
    volatile PBYTE  m_DMARxBuffer_phy;              // physical address of DMA buffer for Rx
    volatile PBYTE  m_DMARxDescriptor;               // virtual address of DMA descriptor for Rx
    volatile PBYTE  m_DMARxDescriptor_phy;       // physical address of DMA descriptor for Rx

    XLLP_DMAC_COMMAND_T      TxCommand;
    XLLP_DMAC_COMMAND_T      RxCommand;

    // IPM variables
    TCHAR                   szName[MAX_NAMELEN];     // device name, eg "FFUART"
    UCHAR                   ucSupportedStatesMask;   // which of D0-D4 driver supports
    CLIENT_ID               ClientID;                // IPM ClientID

    UCHAR m_LineStatus;
};

#endif
